'\" et
.TH PTHREAD_ATFORK "3P" 2017 "IEEE/The Open Group" "POSIX Programmer's Manual"
.\"
.SH PROLOG
This manual page is part of the POSIX Programmer's Manual.
The Linux implementation of this interface may differ (consult
the corresponding Linux manual page for details of Linux behavior),
or the interface may not be implemented on Linux.
.\"
.SH NAME
pthread_atfork
\(em register fork handlers
.SH SYNOPSIS
.LP
.nf
#include <pthread.h>
.P
int pthread_atfork(void (*\fIprepare\fP)(void), void (*\fIparent\fP)(void),
    void (*\fIchild\fP)(void));
.fi
.SH DESCRIPTION
The
\fIpthread_atfork\fR()
function shall declare fork handlers to be called before and after
\fIfork\fR(),
in the context of the thread that called
\fIfork\fR().
The
.IR prepare
fork handler shall be called before
\fIfork\fR()
processing commences. The
.IR parent
fork handle shall be called after
\fIfork\fR()
processing completes in the parent process. The
.IR child
fork handler shall be called after
\fIfork\fR()
processing completes in the child process. If no handling is desired
at one or more of these three points, the corresponding fork handler
address(es) may be set to NULL.
.P
If a
\fIfork\fR()
call in a multi-threaded process leads to a
.IR child
fork handler calling any function that is not async-signal-safe, the
behavior is undefined.
.P
The order of calls to
\fIpthread_atfork\fR()
is significant. The
.IR parent
and
.IR child
fork handlers shall be called in the order in which they were
established by calls to
\fIpthread_atfork\fR().
The
.IR prepare
fork handlers shall be called in the opposite order.
.SH "RETURN VALUE"
Upon successful completion,
\fIpthread_atfork\fR()
shall return a value of zero; otherwise, an error number shall be
returned to indicate the error.
.SH ERRORS
The
\fIpthread_atfork\fR()
function shall fail if:
.TP
.BR ENOMEM
Insufficient table space exists to record the fork handler addresses.
.P
The
\fIpthread_atfork\fR()
function shall not return an error code of
.BR [EINTR] .
.LP
.IR "The following sections are informative."
.SH EXAMPLES
None.
.SH "APPLICATION USAGE"
The original usage pattern envisaged for
\fIpthread_atfork\fR()
was for the
.IR prepare
fork handler to lock mutexes and other locks, and for the
.IR parent
and
.IR child
handlers to unlock them. However, since all of the relevant unlocking
functions, except
\fIsem_post\fR(),
are not async-signal-safe, this usage results in undefined behavior in
the child process unless the only such unlocking function it calls is
\fIsem_post\fR().
.SH RATIONALE
There are at least two serious problems with the semantics of
\fIfork\fR()
in a multi-threaded program. One problem has to do with state (for
example, memory) covered by mutexes. Consider the case where one
thread has a mutex locked and the state covered by that mutex is
inconsistent while another thread calls
\fIfork\fR().
In the child, the mutex is in the locked state (locked by a nonexistent
thread and thus can never be unlocked). Having the child simply
reinitialize the mutex is unsatisfactory since this approach does not
resolve the question about how to correct or otherwise deal with the
inconsistent state in the child.
.P
It is suggested that programs that use
\fIfork\fR()
call an
.IR exec
function very soon afterwards in the child process, thus resetting all
states. In the meantime, only a short list of async-signal-safe
library routines are promised to be available.
.P
Unfortunately, this solution does not address the needs of
multi-threaded libraries. Application programs may not be aware that a
multi-threaded library is in use, and they feel free to call any number
of library routines between the
\fIfork\fR()
and
.IR exec
calls, just as they always have. Indeed, they may be extant
single-threaded programs and cannot, therefore, be expected to obey new
restrictions imposed by the threads library.
.P
On the other hand, the multi-threaded library needs a way to protect
its internal state during
\fIfork\fR()
in case it is re-entered later in the child process. The problem
arises especially in multi-threaded I/O libraries, which are almost
sure to be invoked between the
\fIfork\fR()
and
.IR exec
calls to effect I/O redirection. The solution may require locking
mutex variables during
\fIfork\fR(),
or it may entail simply resetting the state in the child after the
\fIfork\fR()
processing completes.
.P
The
\fIpthread_atfork\fR()
function was intended to provide multi-threaded libraries with a means
to protect themselves from innocent application programs that call
\fIfork\fR(),
and to provide multi-threaded application programs with a standard
mechanism for protecting themselves from
\fIfork\fR()
calls in a library routine or the application itself.
.P
The expected usage was that the prepare handler would acquire all mutex
locks and the other two fork handlers would release them.
.P
For example, an application could have supplied a prepare routine that
acquires the necessary mutexes the library maintains and supplied child
and parent routines that release those mutexes, thus ensuring that the
child would have got a consistent snapshot of the state of the library
(and that no mutexes would have been left stranded). This is good in
theory, but in reality not practical. Each and every mutex and lock
in the process must be located and locked. Every component of a program
including third-party components must participate and they must agree who
is responsible for which mutex or lock. This is especially problematic
for mutexes and locks in dynamically allocated memory. All mutexes and
locks internal to the implementation must be locked, too. This possibly
delays the thread calling
\fIfork\fR()
for a long time or even indefinitely since uses of these synchronization
objects may not be under control of the application. A final problem
to mention here is the problem of locking streams. At least the streams
under control of the system (like
.IR stdin ,
.IR stdout ,
.IR stderr )
must be protected by locking the stream with
\fIflockfile\fR().
But the application itself could have done that, possibly in the same
thread calling
\fIfork\fR().
In this case, the process will deadlock.
.P
Alternatively, some libraries might have been able to supply just a
.IR child
routine that reinitializes the mutexes in the library and all associated
states to some known value (for example, what it was when the image
was originally executed). This approach is not possible, though,
because implementations are allowed to fail
.IR *_init (\|)
and
.IR *_destroy (\|)
calls for mutexes and locks if the mutex or lock is still locked. In
this case, the
.IR child
routine is not able to reinitialize the mutexes and locks.
.P
When
\fIfork\fR()
is called, only the calling thread is duplicated in the child process.
Synchronization variables remain in the same state in the child as they
were in the parent at the time
\fIfork\fR()
was called. Thus, for example, mutex locks may be held by threads that
no longer exist in the child process, and any associated states may
be inconsistent. The intention was that the parent process could have
avoided this by explicit code that acquires and releases locks critical
to the child via
\fIpthread_atfork\fR().
In addition, any critical threads would have needed to be recreated and
reinitialized to the proper state in the child (also via
\fIpthread_atfork\fR()).
.P
A higher-level package may acquire locks on its own data structures
before invoking lower-level packages. Under this scenario, the order
specified for fork handler calls allows a simple rule of initialization
for avoiding package deadlock: a package initializes all packages on
which it depends before it calls the
\fIpthread_atfork\fR()
function for itself.
.P
As explained, there is no suitable solution for functionality which
requires non-atomic operations to be protected through mutexes and
locks. This is why the POSIX.1 standard since the 1996 release requires
that the child process after
\fIfork\fR()
in a multi-threaded process only calls async-signal-safe interfaces.
.SH "FUTURE DIRECTIONS"
The
\fIpthread_atfork\fR()
function may be formally deprecated (for example, by shading it OB) in
a future version of this standard.
.SH "SEE ALSO"
.IR "\fIatexit\fR\^(\|)",
.IR "\fIexec\fR\^",
.IR "\fIfork\fR\^(\|)"
.P
The Base Definitions volume of POSIX.1\(hy2017,
.IR "\fB<pthread.h>\fP",
.IR "\fB<sys_types.h>\fP"
.\"
.SH COPYRIGHT
Portions of this text are reprinted and reproduced in electronic form
from IEEE Std 1003.1-2017, Standard for Information Technology
-- Portable Operating System Interface (POSIX), The Open Group Base
Specifications Issue 7, 2018 Edition,
Copyright (C) 2018 by the Institute of
Electrical and Electronics Engineers, Inc and The Open Group.
In the event of any discrepancy between this version and the original IEEE and
The Open Group Standard, the original IEEE and The Open Group Standard
is the referee document. The original Standard can be obtained online at
http://www.opengroup.org/unix/online.html .
.PP
Any typographical or formatting errors that appear
in this page are most likely
to have been introduced during the conversion of the source files to
man page format. To report such errors, see
https://www.kernel.org/doc/man-pages/reporting_bugs.html .
